package implementation;

import com.thoughtworks.xstream.XStream;
import entities.Movie;
import java.util.ArrayList;
import java.util.List;
import managers.CentralManager;
import managers.MovieManager;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.exist.xmldb.EXistResource;
import org.xmldb.api.base.Collection;
import org.xmldb.api.base.XMLDBException;
import org.xmldb.api.modules.XMLResource;
import utilities.DBUtils;
import utilities.MovieConverter;

/**
 *
 * @author Hacnar
 */
public class MovieManagerImpl implements MovieManager {
    
    @Override
    public Movie createMovie(Movie movie) {
        
        if (movie == null) {
            throw new IllegalArgumentException("Error: movie is null");
        }
        if (movie.getId() != null) {
            throw new IllegalArgumentException("Error: movie has id");
        }
        
        DBUtils.openDBConnection();
        
        Collection col = null;
        XMLResource res = null;
        try {
            col = DBUtils.getOrCreateCollection("/movies");
            
            res = (XMLResource)col.createResource(null, "XMLResource");
            XStream xStream = new XStream();
            xStream.registerConverter(new MovieConverter());
            xStream.alias("movie", Movie.class);
            String resXML = xStream.toXML(movie);
            if (!DBUtils.validate(resXML, "utilities/movie.xsd")) {
                Logger.getLogger(MovieManagerImpl.class.getName()).log(Level.WARN, null);
                return movie;
            }
            res.setContent(xStream.toXML(movie));
            col.storeResource(res);
            movie.setId(res.getId());
        } catch (XMLDBException ex) {
            Logger.getLogger(MovieManagerImpl.class.getName()).log(Level.ERROR, null, ex);
        }
        finally {
            if(res != null) {
                try { ((EXistResource)res).freeResources(); } catch(XMLDBException ex) {
                    Logger.getLogger(MovieManagerImpl.class.getName()).log(Level.ERROR, null, ex);
                }
            }
            
            if(col != null) {
                try { col.close(); } catch(XMLDBException ex) {
                    Logger.getLogger(MovieManagerImpl.class.getName()).log(Level.ERROR, null, ex);
                }
            }
            DBUtils.closeDB();
        }
        return movie;
    }
    
    @Override
    public void updateMovie(Movie movie) {
        if (movie == null) {
            throw new IllegalArgumentException("Error: movie is null");
        }
        if (movie.getId() == null) {
            throw new IllegalArgumentException("Error: movie id is not set");
        }
        
        DBUtils.openDBConnection();
        
        Collection col = null;
        XMLResource res = null;
        try { 
            col = DBUtils.getOrCreateCollection("/movies");
            res = (XMLResource)col.getResource(movie.getId());
            XStream xStream = new XStream();
            xStream.registerConverter(new MovieConverter());
            xStream.alias("movie", Movie.class);
            String resXML = xStream.toXML(movie);
            if (!DBUtils.validate(resXML, "utilities/movie.xsd")) {
                Logger.getLogger(MovieManagerImpl.class.getName()).log(Level.WARN, null);
                return;
            }
            res.setContent(xStream.toXML(movie));
            col.storeResource(res);
        } catch (XMLDBException ex) {
            Logger.getLogger(MovieManagerImpl.class.getName()).log(Level.ERROR, null, ex);
        }
        finally {
            if(res != null) {
                try { ((EXistResource)res).freeResources(); } catch(XMLDBException ex) {
                    Logger.getLogger(MovieManagerImpl.class.getName()).log(Level.ERROR, null, ex);
                }
            }
            
            if(col != null) {
                try { col.close(); } catch(XMLDBException ex) {
                    Logger.getLogger(MovieManagerImpl.class.getName()).log(Level.ERROR, null, ex);
                }
            }
            DBUtils.closeDB();
        }
    }

    @Override
    public void deleteMovie(Movie movie) {
        if (movie == null) {
            throw new IllegalArgumentException("Error: movie is null");
        }
        if (movie.getId() == null) {
            throw new IllegalArgumentException("Error: movie id is not set");
        }
        DBUtils.openDBConnection();
        
        Collection col = null;
        XMLResource res = null;
        try { 
            col = DBUtils.getOrCreateCollection("/movies");
            res = (XMLResource)col.getResource(movie.getId());
            if (res == null) {
                throw new IllegalArgumentException("Error: movie is not in database");
            }
            col.removeResource(res);
        } catch (XMLDBException ex) {
            Logger.getLogger(MovieManagerImpl.class.getName()).log(Level.ERROR, null, ex);
        }
        finally {
            if(res != null) {
                try { ((EXistResource)res).freeResources(); } catch(XMLDBException ex) {
                    Logger.getLogger(MovieManagerImpl.class.getName()).log(Level.ERROR, null, ex);
                }
            }
            if(col != null) {
                try { col.close(); } catch(XMLDBException ex) {
                    Logger.getLogger(MovieManagerImpl.class.getName()).log(Level.ERROR, null, ex);
                }
            }
            DBUtils.closeDB();
        }
    }

    @Override
    public Movie getMovieByID(String id) {
        if (id == null || id.isEmpty()) {
            throw new IllegalArgumentException("Error: id is null or empty");
        }

        CentralManager manager = new CentralManagerImpl();
        DBUtils.openDBConnection();
        Movie movie = null;
        Collection col = null;
        XMLResource res = null;
        try { 
            col = DBUtils.getOrCreateCollection("/movies");
            res = (XMLResource)col.getResource(id);
            if (res == null) {
                throw new IllegalArgumentException("Error: movie is not in database");
            }
            XStream xStream = new XStream();
            xStream.registerConverter(new MovieConverter());
            xStream.alias("movie", Movie.class);
            movie = (Movie)xStream.fromXML("<?xml version=\"1.0\"?>"+res.getContent().toString());
            movie.setId(id);
            List<entities.Medium> listMedium;
            listMedium = manager.getMediaWithMovie(movie);
            if (listMedium.isEmpty()){
                
            } else {
                movie.setMedium(manager.getMediaWithMovie(movie).get(0));
            }
            return movie;
        } catch (XMLDBException ex) {
            Logger.getLogger(MovieManagerImpl.class.getName()).log(Level.ERROR, null, ex);
        }
        finally {
            if(res != null) {
                try { ((EXistResource)res).freeResources(); } catch(XMLDBException ex) {
                    Logger.getLogger(MovieManagerImpl.class.getName()).log(Level.ERROR, null, ex);
                }
            }
            
            if(col != null) {
                try { col.close(); } catch(XMLDBException ex) {
                    Logger.getLogger(MovieManagerImpl.class.getName()).log(Level.ERROR, null, ex);
                }
            }
            DBUtils.closeDB();
        }
        return movie;
    }

    @Override
    public List<Movie> getAllMovies() {
        
        DBUtils.openDBConnection();
        List<Movie> movies = new ArrayList<Movie>();
        try {
            Collection col = DBUtils.getOrCreateCollection("/movies");
            String[] ids = col.listResources();
            int count = col.getResourceCount();
            for (int i = 0; i < count; i++) {
                movies.add(getMovieByID(ids[i]));
            }
        } catch (XMLDBException ex) {
            Logger.getLogger(MovieManagerImpl.class.getName()).log(Level.ERROR, null, ex);
        } finally {
            DBUtils.closeDB();
        }
        
        return movies;
    }
}
